package com.juyu.miliao.api.config;

import com.juyu.miliao.common.dataSource.*;
import com.juyu.miliao.common.dataSource.key.DataSourceKey;
import com.juyu.miliao.common.dataSource.key.DataSourceKeyEvaluator;
import com.juyu.miliao.common.dataSource.tool.distributeOperate.DistributeOperateAspect;
import com.juyu.miliao.common.dataSource.tool.distributeOperate.DistributeResultHandlers;
import com.juyu.miliao.common.dataSource.tool.operate.OperateAspect;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.sql.DataSource;

@Configuration
public class DatabaseConfig {
    @Autowired
    private ResourcePatternResolver resourcePatternResolver;

    @Bean
    public DataSourceKey dataSourceKey() {
        return new DataSourceKey();
    }

    @Bean
    public DataSourceKeyEvaluator dataSourceKeyEvaluator() {
        return new GlobalDataSourceKeyEvaluator();
    }

    @Bean
    public OperateAspect operateAspect(DataSourceKey dataSourceKey, DataSourceKeyEvaluator dataSourceKeyEvaluator) {
        return new OperateAspect(dataSourceKey, dataSourceKeyEvaluator);
    }

    @Bean
    @ConfigurationProperties("app.multiple-datasource")
    public MultipleDataSourceConfig multipleDataSourceConfig() {
        return new MultipleDataSourceConfig();
    }

    @Bean
    public MultipleDataSourceParser multipleDataSourceParser(MultipleDataSourceConfig multipleDataSourceConfig) {
        return MultipleDataSourceParser.builder().setMultipleDataSourceConfig(multipleDataSourceConfig).build();
    }

    @Bean
    public DistributeResultHandlers distributeResultHandlers() {
        return new GlobalDistributeResultHandlers();
    }

    @Bean
    public DistributeOperateAspect distributeSelectAspect(DataSourceKey dataSourceKey, DataSourceKeyEvaluator dataSourceKeyEvaluator,
                                                          MultipleDataSourceParser multipleDataSourceParser, DistributeResultHandlers distributeResultHandlers) {
        return new DistributeOperateAspect(dataSourceKey, dataSourceKeyEvaluator, multipleDataSourceParser, distributeResultHandlers);
    }

    @Bean
    public MultipleDataSource dataSource(MultipleDataSourceParser multipleDataSourceParser, DataSourceKey dataSourceKey) {
        MultipleDataSource multipleDataSource = new MultipleDataSource(dataSourceKey);
        multipleDataSource.setDefaultTargetDataSource(multipleDataSourceParser.getDefaultDataSource());
        multipleDataSource.setLenientFallback(false);
        multipleDataSource.setTargetDataSources(multipleDataSourceParser.getDataSourceMap());
        return multipleDataSource;
    }

    private SqlSessionFactory createSqlSessionFactory(Object key, Object dataSource) {
        try{
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource((DataSource)dataSource);
            Resource[] resources = resourcePatternResolver
                    .getResources("classpath*:com/juyu/miliao/api/dao/mysql/*.xml");
            sqlSessionFactoryBean.setMapperLocations(resources);
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            configuration.setMapUnderscoreToCamelCase(true);
            sqlSessionFactoryBean.setConfiguration(configuration);
            return sqlSessionFactoryBean.getObject();
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }

    @Bean
    public SqlSession sqlSession(DataSourceKey dataSourceKey, MultipleDataSourceParser multipleDataSourceParser) throws Exception {
        MultipleSqlSessionFactoryParser parser = MultipleSqlSessionFactoryParser.builder()
                .setMultipleDataSourceParser(multipleDataSourceParser)
                .setSqlSessionFactoryCreater(this::createSqlSessionFactory)
                .build();
        return new MutipleSqlSessionTemplate(dataSourceKey, parser.getDefaultSqlSessionFactory(), parser.getSqlSessionFactoryMap());
    }

    @Bean
    public IdCreater idCreater(StringRedisTemplate stringRedisTemplate, MultipleDataSourceParser multipleDataSourceParser) {
        return new IdCreater(stringRedisTemplate, multipleDataSourceParser);
    }

}
